package com.ddwl.wallet.service;


import com.ddwl.common.constant.DistConstant;
import com.ddwl.common.exception.ParamException;
import com.ddwl.common.util.BeanConverUtils;
import com.ddwl.common.util.MySqlUtil;
import com.ddwl.common.util.UUIDGenerator;
import com.ddwl.schema.bo.base.PageBo;
import com.ddwl.schema.bo.wallet.OldSalesRankBo;
import com.ddwl.schema.bo.wallet.WalletFlowQueryBo;
import com.ddwl.schema.bo.wallet.WalletFlowStatisticsQueryBo;
import com.ddwl.schema.vo.base.PageVo;
import com.ddwl.schema.vo.wallet.OldSalesRankVo;
import com.ddwl.schema.vo.wallet.UserWalletFlowVo;
import com.ddwl.schema.vo.wallet.UserWalletMainReportVo;
import com.ddwl.schema.vo.wallet.UserWalletVo;
import com.ddwl.wallet.dao.OldSalesRankDao;
import com.ddwl.wallet.dao.UserWalletDao;
import com.ddwl.wallet.dao.UserWalletFlowDao;
import com.ddwl.wallet.dao.dto.WalletFlowStatisticsDto;
import com.ddwl.wallet.dao.model.DistOrder;
import com.ddwl.wallet.dao.model.OldSalesRank;
import com.ddwl.wallet.dao.model.UserWallet;
import com.ddwl.wallet.dao.model.UserWalletFlow;
import com.ddwl.wallet.service.dto.UserWalletChangeDto;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.BeanUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class UserWalletService {

    @Resource
    private UserWalletDao userWalletDao;
    @Lazy
    @Resource
    private DistOrderService distOrderService;
    @Resource
    private UserWalletFlowDao userWalletFlowDao;
    @Resource
    private OldSalesRankDao oldSalesRankDao;


    /**
     * 查询用户资金流水变更报表
     *
     * @param bo
     * @return
     */
    public PageVo<WalletFlowStatisticsDto> queryMoneyFlowReport(PageBo<WalletFlowStatisticsQueryBo> bo) {
        PageHelper.startPage(bo.getPage(), bo.getPageSize(), MySqlUtil.orderBy(bo.getSort(), bo.isAsc()));
        PageInfo<WalletFlowStatisticsDto> info = new PageInfo(userWalletFlowDao.queryPayoffMonthlyReport(bo.getParam()));
        return new PageVo<>(info.getTotal(), bo.getPage(), bo.getPageSize(), info.getList());
    }


    /**
     * 查询用户资金变动流水
     *
     * @param bo
     * @return
     */
    public PageVo<UserWalletFlowVo> queryMoneyFlow(PageBo<WalletFlowQueryBo> bo) {
        PageHelper.startPage(bo.getPage(), bo.getPageSize(), MySqlUtil.orderBy(bo.getSort(), bo.isAsc()));
        PageInfo<UserWalletFlowVo> info = new PageInfo(userWalletFlowDao.queryWalletFlow(bo.getParam()));
        return new PageVo<>(info.getTotal(), bo.getPage(), bo.getPageSize(), info.getList());
    }

    /**
     * 获取用户钱包信息
     *
     * @return
     */
    public UserWalletVo getUserWalletEstimate(String userId) {
        UserWalletVo walletVo = BeanConverUtils.convertBean(userWalletDao.getUserWallet(userId), UserWalletVo.class);
        walletVo.setAtMonthAmount(distOrderService.getUserAtMonth(userId));
        walletVo.setBeforeMonthAmount(distOrderService.getUserBeforeMonth(userId));
        return walletVo;
    }

    public UserWalletVo getUserWallet(String userId) {
        UserWalletVo walletVo = BeanConverUtils.convertBean(userWalletDao.getUserWallet(userId), UserWalletVo.class);
        return walletVo;
    }

    public UserWalletMainReportVo getUserWalletReportVo(String userId) {
        UserWalletMainReportVo userWalletMainReportVo = distOrderService.walletMainReport(userId);
        userWalletMainReportVo.setAmount(userWalletDao.getUserWallet(userId).getAvailableAmount());
        return userWalletMainReportVo;
    }

    /**
     * 五八马店铺获取店铺佣金
     *
     * @param userId
     * @return
     */
    public UserWalletMainReportVo wbmShopWallet(String userId) {
        UserWalletMainReportVo userWalletMainReportVo = distOrderService.walletMainReport(userId);
        userWalletMainReportVo.setAmount(userWalletDao.getUserWallet(userId).getAvailableAmount());
        return userWalletMainReportVo;
    }

    /**
     * 冻结用户账号金额
     */
    public void freezeUserAmount(String userId, BigDecimal bigDecimal, DistConstant.WalletFlowType walletFlowType, String flowId) {
        UserWallet userWallet = userWalletDao.getUserWallet(userId);
        ParamException.isTrue(userWallet.getAvailableAmount().compareTo(bigDecimal) < 0, "余额不足");
        UserWallet update = new UserWallet();
        update.setId(userWallet.getId());
        update.setAvailableAmount(userWallet.getAvailableAmount().subtract(bigDecimal));
        update.setFrozenAmount(userWallet.getFrozenAmount().add(bigDecimal));
        userWalletDao.updateByPrimaryKeySelective(update);
        UserWalletFlow userWalletFlow = new UserWalletFlow();
        userWalletFlow.setAfterAmount(userWallet.getAvailableAmount().subtract(bigDecimal));
        userWalletFlow.setBeforeAmount(userWallet.getAvailableAmount());
        userWalletFlow.setChangeAmount(bigDecimal);
        userWalletFlow.setMsg(walletFlowType.getMsg());
        userWalletFlow.setType(walletFlowType.getType());
        userWalletFlow.setTransactionType(walletFlowType.getTransactionType());
        userWalletFlow.setUserId(userId);
        userWalletFlow.setChangeRecord(flowId);
        userWalletFlowDao.insert(userWalletFlow);
    }

    /**
     * 解冻用户账号金额(提现失败调用)
     */
    public void unfreezeUserAmount(String userId, BigDecimal bigDecimal, DistConstant.WalletFlowType walletFlowType, String flowId) {
        UserWallet userWallet = userWalletDao.getUserWallet(userId);
        ParamException.isTrue(userWallet.getFrozenAmount().compareTo(bigDecimal) < 0, "冻结金额不足");
        UserWallet update = new UserWallet();
        update.setId(userWallet.getId());
        update.setAvailableAmount(userWallet.getAvailableAmount().add(bigDecimal));
        update.setFrozenAmount(userWallet.getFrozenAmount().subtract(bigDecimal));
        userWalletDao.updateByPrimaryKeySelective(update);
        UserWalletFlow userWalletFlow = new UserWalletFlow();
        userWalletFlow.setAfterAmount(userWallet.getAvailableAmount().add(bigDecimal));
        userWalletFlow.setBeforeAmount(userWallet.getAvailableAmount());
        userWalletFlow.setChangeAmount(bigDecimal);
        userWalletFlow.setMsg(walletFlowType.getMsg());
        userWalletFlow.setType(walletFlowType.getType());
        userWalletFlow.setTransactionType(walletFlowType.getTransactionType());
        userWalletFlow.setUserId(userId);
        userWalletFlow.setChangeRecord(flowId);
        userWalletFlowDao.insert(userWalletFlow);
    }

    /**
     * 扣除冻结用户账号金额（提现成功调用）
     */
    public void deductFreezeUserAmount(String userId, BigDecimal bigDecimal) {
        UserWallet userWallet = userWalletDao.getUserWallet(userId);
        ParamException.isTrue(userWallet.getFrozenAmount().compareTo(bigDecimal) < 0, "冻结金额不足");
        UserWallet update = new UserWallet();
        update.setId(userWallet.getId());
        update.setFrozenAmount(userWallet.getFrozenAmount().subtract(bigDecimal));
        userWalletDao.updateByPrimaryKeySelective(update);
    }

    public void changeUserWallet(String changeRecord, String userId, Integer type, BigDecimal amount){
        DistConstant.WalletFlowType walletFlowType = DistConstant.WalletFlowType.getWalletFlowType(type);
        UserWalletChangeDto dto = UserWalletChangeDto.buildUserWalletChangeDto(changeRecord, userId, walletFlowType, amount);
        userWalletChange(dto);
    }

    /**
     * 变动账号金额
     *
     * @param dto
     */
    @Transactional(rollbackFor = Exception.class)
    public synchronized void userWalletChange(UserWalletChangeDto dto) {
        UserWallet userWallet = userWalletDao.getUserWallet(dto.getUserId());
        UserWalletFlow userWalletFlow = BeanConverUtils.convertBean(dto, UserWalletFlow.class);
        //收入
        if (DistConstant.WalletFlowChangeType.SR.getCode().equals(dto.getTransactionType())) {
            userWalletFlow.setAfterAmount(userWallet.getAvailableAmount().add(dto.getChangeAmount()));
            userWalletFlow.setBeforeAmount(userWallet.getAvailableAmount());
            userWallet.setAvailableAmount(userWallet.getAvailableAmount().add(dto.getChangeAmount()));
            //支出
        } else {
            userWalletFlow.setAfterAmount(userWallet.getAvailableAmount().subtract(dto.getChangeAmount()));
            userWalletFlow.setBeforeAmount(userWallet.getAvailableAmount());
            userWallet.setAvailableAmount(userWallet.getAvailableAmount().subtract(dto.getChangeAmount()));
        }
        userWalletDao.updateByPrimaryKeySelective(userWallet);
        userWalletFlowDao.insert(userWalletFlow);
    }


    @Transactional(rollbackFor = Throwable.class)
    public String createOldSalesRank(OldSalesRankBo bo) {
        OldSalesRank entity = new OldSalesRank();
        BeanUtils.copyProperties(bo, entity);
        //创建或更新
        if (entity.getId() != null && !entity.getId().isEmpty()) {
            oldSalesRankDao.updateByPrimaryKeySelective(entity);
        } else {
            entity.setName(bo.getName());
            entity.setTel(bo.getTel());
            OldSalesRank oldSalesRank = oldSalesRankDao.selectOne(entity);
            ParamException.isNotNull(oldSalesRank, "同一个用户只能生成一条数据");
            oldSalesRankDao.insert(entity);
        }
        return entity.getId();
    }


    public PageVo<OldSalesRankVo> oldSalesRankList(PageBo<OldSalesRankBo> pageBo) {
        PageHelper.startPage(pageBo.getPage(), pageBo.getPageSize(), MySqlUtil.orderBy(pageBo.getSort(), pageBo.isAsc()));
        OldSalesRankBo bo = pageBo.getParam();
        OldSalesRank entity = new OldSalesRank();
        BeanUtils.copyProperties(bo, entity);
        List<OldSalesRank> entities = oldSalesRankDao.select(entity);
        PageInfo<OldSalesRank> info = new PageInfo(entities);
        List<OldSalesRankVo> joinerVos = BeanConverUtils.convertBeanList(entities, OldSalesRankVo.class);
        return new PageVo<>(info.getTotal(), pageBo.getPage(), pageBo.getPageSize(), joinerVos);
    }

    @Transactional(rollbackFor = Exception.class)
    public void correctWalletInfo(String fxUserId, String userId) {
        correctDistOrder(fxUserId, userId);
        correctWall(fxUserId, userId);
        correctWalletFlow(fxUserId, userId);
    }

    private void correctWalletFlow(String fxUserId, String userId) {
        List<UserWalletFlow> list = userWalletFlowDao.getWalletFlow(userId);
        list.forEach(userWalletFlow -> {
            userWalletFlowDao.deleteById(userWalletFlow.getId());
            userWalletFlow.setId(UUIDGenerator.getShortUUID());
            userWalletFlow.setUserId(fxUserId);
            userWalletFlowDao.copyInsert(userWalletFlow);
        });
    }

    private void correctWall(String fxUserId, String userId) {
        UserWallet userWallet = userWalletDao.getExistWallet(userId);
        if (null != userWallet) {
            userWalletDao.deleteById(userWallet.getId());
            userWallet.setId(UUIDGenerator.getShortUUID());
            userWallet.setUserId(fxUserId);
            userWalletDao.copyInsert(userWallet);
        }
    }

    private void correctDistOrder(String fxUserId, String userId) {
        List<DistOrder> list = distOrderService.queryByUserId(userId);
        if (null != list && !list.isEmpty()) {
            list.forEach(distOrder -> {
                distOrderService.correctDistOrder(fxUserId, distOrder);
            });
        }
    }

    public Map<String, BigDecimal> queryUserWalletList(List<String> userIds) {
        if (CollectionUtils.isEmpty(userIds)) {
            return null;
        }
        List<UserWallet> userWallets = userWalletDao.queryUserWalletList(userIds);
        if (CollectionUtils.isEmpty(userWallets)) {
            return new HashMap<>();
        }
        return userWallets.stream().collect(Collectors.toMap(UserWallet::getUserId, UserWallet::getAvailableAmount, (uw, uw1) -> uw1));
    }

}
